import * as THREE from "three";
import { MOUSE, Raycaster } from "three";
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
import Stats from 'three/examples/jsm/libs/stats.module.js';

export function init(container: HTMLDivElement): THREE.Scene {
  // 创建场景
  const scene = new THREE.Scene();

  scene.background = new THREE.Color(0xeeeeee);

  const width = container.offsetWidth;
  const height = container.offsetHeight;

  // 创建相机
  const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);

  // (x,y,z)
  camera.position.set(0, 0, 40); // 投影相机设置这个可以实现缩放

  camera.zoom = 1; // 投影相机设置缩放倍速没用

  // 将相机添加到场景(不需要)
  // scene.add(camera);

  // 初始化渲染器 antialias: true -- 抗锯齿，解决锯齿严重问题
  const renderer = new THREE.WebGLRenderer({ antialias: true });
  // renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染尺寸大小
  renderer.setSize(width, height); // 设置渲染尺寸大小

  // 创建轨道控制器，需要绑定： (控制的相机, 事件监听的html元素)
  const controls = new OrbitControls(camera, renderer.domElement);

  // 添加坐标轴辅助器，长度为20
  const axesHelper = new THREE.AxesHelper(20);
  scene.add(axesHelper);

  // 将webgl渲染的canvas内容添加到容器
  container.appendChild(renderer.domElement);

  // requestAnimationFrame，由于是异步调用，调用的时机可能不均匀
  function render() {
    controls.update();
    renderer.render(scene, camera); // 渲染
    // 渲染下一帧的时候会调用render函数
    requestAnimationFrame(render);
  }

  render();

  return scene;
}

type Helper = THREE.CameraHelper | THREE.DirectionalLightHelper;

export function initAppDetail(container: HTMLDivElement, isNeedAutoRender: boolean = true, isNeedRayTest: boolean = true): AppMsg {
  // 用于刷新helper
  const helpers: Helper[] = [];

  // 创建场景
  const scene = new THREE.Scene();

  // scene.background = new THREE.Color(0xcccccc)
  scene.background = new THREE.Color(0xeeeeee);

  // 这里获取offsetWidth必须该dom是可见的，也就是加入到dom树中的
  const width = container.offsetWidth;
  const height = container.offsetHeight;

  // console.log("@offsetSize:", width, height)
  // 创建相机
  const camera = new THREE.PerspectiveCamera(
    45,
    width / height,
    0.1,
    100000000
  );

  // (x,y,z)
  camera.position.set(0, 0, 40); // 投影相机设置这个可以实现缩放

  camera.zoom = 1; // 投影相机设置缩放倍速没用

  // 将相机添加到场景(不需要)
  // scene.add(camera);

  // 初始化渲染器 antialias: true -- 抗锯齿，解决锯齿严重问题
  const renderer = new THREE.WebGLRenderer({
    antialias: true,
  });
  // renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染尺寸大小
  renderer.setSize(width, height); // 设置渲染尺寸大小

  // 创建轨道控制器，需要绑定： (控制的相机, 事件监听的html元素)
  const controls = new OrbitControls(camera, renderer.domElement);

  // 添加坐标轴辅助器，长度为20
  const axesHelper = new THREE.AxesHelper(2000);
  axesHelper.name = "axesHelper";
  scene.add(axesHelper);

  // 将webgl渲染的canvas内容添加到容器
  container.appendChild(renderer.domElement);

  // 响应事件
  if (isNeedRayTest) {
    container.addEventListener(
      "mousedown",
      (event) => {
        const px = event.offsetX;
        const py = event.offsetY;

        const x = (px / width) * 2 - 1;
        const y = -(py / height) * 2 + 1;

        // console.log(px, py, width, height, x, y);

        const raycaster = new Raycaster();

        // 形象点说就是在点击位置创建一条射线，射线穿过的模型代表选中
        raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
        //.intersectObjects([mesh1, mesh2, mesh3])对参数中的网格模型对象进行射线交叉计算
        // 未选中对象返回空数组[],选中一个对象，数组1个元素，选中两个对象，数组两个元素
        const intersects = raycaster.intersectObjects([...scene.children]);
        // console.log("射线可选中的网格：", scene.children)
        console.log("射线器返回的对象", intersects);
        // intersects.length大于0说明，说明选中了模型
        if (intersects.length > 0) {
          console.log("@第一个:", intersects[0]);
        }
      },
      false
    );
  }

  const stats = new Stats();
  stats.showPanel(0); // 1 显示 GPU 时间
  // 设置监视器位置
  stats.dom.style.position = "absolute";
  stats.dom.style.left = "0px";
  stats.dom.style.top = "0px";

  if(isNeedAutoRender) {
    document.body.appendChild(stats.dom);
    render();
  }

  // requestAnimationFrame，由于是异步调用，调用的时机可能不均匀
  function render() {
    stats.begin();
    helpers.forEach((helper) => {
      helper.update();
    });

    controls.update();
    renderer.render(scene, camera); // 渲染
    // 渲染下一帧的时候会调用render函数

    stats.end();
    requestAnimationFrame(render);
  }

  return {
    helpers: helpers,
    scene: scene,
    renderer: renderer,
    camera: camera,
    controls: controls,
  };
}

export interface IMyThreeApp {
  scene: THREE.Scene;
  renderer: THREE.WebGLRenderer;
  render: () => void;
}

export interface AppMsg {
  scene: THREE.Scene;
  renderer: THREE.WebGLRenderer;
  camera: THREE.Camera;
  helpers: Helper[];
  controls?: OrbitControls;
  composer?: EffectComposer;
}
